
import { fileType, fileIcon, imgType, videoType } from '@/config/fileConfig'

import sparkMD5 from 'spark-md5'

import * as fileApi from '@/api/base/file'

export const checkImgSize = (img, imgLimit) => {
  if (imgLimit.Ratio != null) {
    const sRatio = Math.round(
      (imgLimit.Ratio[0] / imgLimit.Ratio[1]) * 100
    )
    const ratio = Math.round((img.width / img.height) * 100)
    if (sRatio !== ratio) {
      return false
    }
  }
  if (imgLimit.MinWidth != null && img.width < imgLimit.MinWidth) {
    return false
  }
  if (imgLimit.MinHeight != null && img.height < imgLimit.MinHeight) {
    return false
  }
  if (imgLimit.MaxHeight != null && img.height > imgLimit.MaxHeight) {
    return false
  }
  if (imgLimit.MaxWidth != null && img.width > imgLimit.MaxWidth) {
    return false
  }
  return true
}
export const checkImg = (file, imgLimit) => {
  return new Promise((resolve) => {
    if (imgLimit == null) {
      resolve(true)
      return
    }
    const reader = new FileReader()
    reader.onload = function(e) {
      const img = new Image()
      img.onload = function() {
        resolve(checkImgSize(img, imgLimit))
      }
      img.src = e.target.result
    }
    reader.readAsDataURL(file)
  })
}
export const getFileType = (type, name) => {
  const t = fileType[type]
  if (t != null && t !== undefined) {
    return t
  }
  const index = name.lastIndexOf('.')
  if (index === -1) {
    return null
  }
  return name.substring(index).toLowerCase()
}

export const getFileExt = (name) => {
  const index = name.lastIndexOf('.')
  if (index === -1) {
    return null
  }
  return name.substring(index).toLowerCase()
}

export const getFileIcon = (type) => {
  const icon = fileIcon[type]
  if (icon) {
    return icon
  }
  return fileIcon['def']
}
export const initFile = (item, file) => {
  const type = getFileExt(item.FileName)
  item.ext = type
  if (imgType.includes(type)) {
    item.type = 'img'
    if (file != null && item.FileUri == null) {
      item.FileUri = URL.createObjectURL(file)
    }
  } else if (videoType.includes(type)) {
    item.type = 'video'
    if (item.status === 'ready') {
      item.icon = getFileIcon(type)
    } else {
      item.thumbnai = fileApi.getUserThumbnailUri(item.FileId)
    }
  } else {
    item.type = 'file'
    item.icon = getFileIcon(type)
  }
}
export const checkIsImg = (type) => {
  return imgType.includes(type)
}
export const loadMD5 = (file) => {
  const blobSlice =
      File.prototype.slice ||
      File.prototype.mozSlice ||
      File.prototype.webkitSlice
  const chunkSize = 20971520 * 2.5
  const chunks = Math.ceil(file.size / chunkSize)
  return new Promise((resolve, reject) => {
    let currentChunk = 0
    const spark = new sparkMD5.ArrayBuffer()
    const reader = new FileReader()
    reader.onload = function(e) {
      spark.append(e.target.result)
      currentChunk++
      if (currentChunk < chunks) {
        loadNext()
      } else {
        resolve(spark.end())
      }
    }
    reader.onerror = function() {
      reject()
    }

    function loadNext() {
      const start = currentChunk * chunkSize
      const end =
          start + chunkSize >= file.size ? file.size : start + chunkSize
      reader.readAsArrayBuffer(blobSlice.call(file, start, end))
    }
    loadNext()
  })
}
export const blockUp = async(data, md5, file, progress, cancel) => {
  if (cancel == null) {
    cancel = {
      isCancel: false
    }
  }
  const taskId = await fileApi.blockUpFile({
    FileName: file.name,
    FileSize: file.size,
    FileMd5: md5,
    Form: data
  })
  do {
    const res = await getUpState(taskId)
    if (res.UpState === 3) {
      return res.Result
    }
    const upRes = await beginUp(taskId, res.Block, file, progress, cancel)
    if (!upRes || cancel.isCancel) {
      return null
    }
  // eslint-disable-next-line no-constant-condition
  } while (true)
}

export const beginUp = async(taskId, res, file, progress, cancel) => {
  const size = parseInt(res.BlockSize)
  res.FileSize = parseInt(res.FileSize)
  res.AlreadyUp = parseInt(res.AlreadyUp)
  let val = Math.round((res.AlreadyUp / res.FileSize) * 10000) / 100
  if (val > 100) {
    val = 100
  }
  progress(val)
  const tasks = res.NoUpIndex.map(i => {
    const begin = i * size
    let end = begin + size
    if (end > res.FileSize) {
      end = res.FileSize
    }
    return {
      index: i,
      begin: begin,
      end: end,
      isEnd: false,
      retry: 0
    }
  })
  if (tasks.length === 0) {
    return false
  }
  return await upBlockFile(file, taskId, tasks, 0, (num) => {
    res.AlreadyUp = res.AlreadyUp + num
    let val = Math.round((res.AlreadyUp / res.FileSize) * 10000) / 100
    if (val > 100) {
      val = 100
    }
    progress(val)
  }, cancel)
}
export const upBlockFile = async(file, taskId, tasks, index, action, cancel) => {
  const task = tasks[index]
  if (!task.isEnd) {
    try {
      await fileApi.upBlockFile(file, taskId, task, action)
      task.isEnd = true
      index = index + 1
    } catch (e) {
      if (e.errorcode === '10557053896229525') {
        task.isEnd = true
        index = index + 1
      } else {
        task.isEnd = false
        task.retry = task.retry + 1
        if (task.retry >= 3) {
          return false
        }
      }
    }
  } else {
    index = index + 1
  }
  if (index >= tasks.length || cancel.isCancel) {
    return true
  }
  return await upBlockFile(file, taskId, tasks, index, action, cancel)
}
export const getUpState = async(taskId) => {
  const res = await fileApi.getUpState(taskId)
  if (res.UpState === 0 || res.UpState === 2 || res.UpState === 4) {
    return await new Promise((resolve, reject) => {
      window.setTimeout(async() => {
        try {
          const data = await getUpState(taskId)
          resolve(data)
        } catch {
          reject()
        }
      }, 1000)
    })
  }
  return res
}
